//
//  Demo2.cpp
//  OpenGLDemo1
//
//  Created by HFY on 2018/6/21.
//  Copyright © 2018年 Demo. All rights reserved.
//

#define STB_IMAGE_IMPLEMENTATION
#include "Demo2.hpp"
#include <iostream>
#include <GLFW/glfw3.h>
#include "stb_image.h"

float vertices[] = {
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};
glm::vec3 cubePositions[] = {
    glm::vec3( 0.0f,  0.0f,  0.0f),
    glm::vec3( 2.0f,  5.0f, -15.0f),
    glm::vec3(-1.5f, -2.2f, -2.5f),
    glm::vec3(-3.8f, -2.0f, -12.3f),
    glm::vec3( 2.4f, -0.4f, -3.5f),
    glm::vec3(-1.7f,  3.0f, -7.5f),
    glm::vec3( 1.3f, -2.0f, -2.5f),
    glm::vec3( 1.5f,  2.0f, -2.5f),
    glm::vec3( 1.5f,  0.2f, -1.5f),
    glm::vec3(-1.3f,  1.0f, -1.5f)
};

void printVec4(glm::vec4 vec) {
    std::cout << "vec detail: (" << vec.x << ", " << vec.y << ", " << vec.z << ")" << std::endl;
}

void testGLM() {
    glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
    glm::mat4 trans = glm::mat4(1.0);
    trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
    vec = trans * vec;
    
    printVec4(vec);
}

Demo2::Demo2() {
    shader = new Shader("/Users/hfy/Desktop/Code/OpenGL/OpenGLDemo1/OpenGLDemo1/texture/shader.vert",
                        "/Users/hfy/Desktop/Code/OpenGL/OpenGLDemo1/OpenGLDemo1/texture/shader.frag");
    const char *texture0Path = "/Users/hfy/Desktop/Code/OpenGL/OpenGLDemo1/OpenGLDemo1/images/container.jpg";
    const char *texture1Path = "/Users/hfy/Desktop/Code/OpenGL/OpenGLDemo1/OpenGLDemo1/images/awesomeface.png";
    int width0, height0, nrChannels0;
    int width1, height1, nrChannels1;
    stbi_set_flip_vertically_on_load(true);
    unsigned char *data0 = stbi_load(texture0Path, &width0, &height0, &nrChannels0, 0);
    unsigned char *data1 = stbi_load(texture1Path, &width1, &height1, &nrChannels1, 0);
    std::cout << "texture0: (" << width0 << ", " << height0 << ", " << nrChannels0 << ")" << std::endl;
    std::cout << "texture1: (" << width1 << ", " << height1 << ", " << nrChannels1 << ")" << std::endl;
    
    if (data0) {
        // 初始化相机位置信息
        cameraPosition = glm::vec3(0.0f, 0.0f, 3.0f);
        cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
        cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
        
        // 加载并创建texture0
        glGenTextures(1, &texture0);
        glBindTexture(GL_TEXTURE_2D, texture0);
        // 为当前绑定的纹理对象设置环绕、过滤方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width0, height0, 0, GL_RGB, GL_UNSIGNED_BYTE, data0);
        glGenerateMipmap(GL_TEXTURE_2D);
        
        // 加载并创建texture1
        glGenTextures(1, &texture1);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data1);
        glGenerateMipmap(GL_TEXTURE_2D);
        
        // 绘制图形
//        // 配置顶点数据
//        float vertices[] = {
//            0.8f, 0.8f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // 右上
//            0.8f, -0.8f, 0.0f,  0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // 右下
//            -0.8f, -0.8f, 0.0f, 0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // 左下
//            -0.8f, 0.8f, 0.0f,  1.0f, 1.0f, 0.0f,   0.0f, 1.0f, // 左上
//        };
//        unsigned int indices[] = {
//            0, 1, 2,
//            0, 2, 3
//        };
//        glGenVertexArrays(1, &VAO);
//        glBindVertexArray(VAO);
//
//        glGenBuffers(1, &VBO);
//        glBindBuffer(GL_ARRAY_BUFFER, VBO);
//        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
//        glEnableVertexAttribArray(0);
//        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
//        glEnableVertexAttribArray(1);
//        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
//        glEnableVertexAttribArray(2);
//
//        glGenBuffers(1, &EBO);
//        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
        
        // 配置正方体
        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);
        
        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
        glEnableVertexAttribArray(1);
        
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
        
        glEnable(GL_DEPTH_TEST);
    } else {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data0);
    stbi_image_free(data1);
    
}

void Demo2::updateTranform(int i) {
    transform = glm::mat4(1.0);
    transform = glm::translate(transform, glm::vec3(0.5, -0.5, 0.0));
    transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0, 0.0, 1.0));
    transform = glm::scale(transform, glm::vec3(0.5, 0.5, 0.5));
    shader -> setMatrix4f("transform", glm::value_ptr(transform));
    
    glm::mat4 modelMatrix(1.0);
    modelMatrix = glm::translate(modelMatrix, cubePositions[i]);
//    modelMatrix = glm::rotate(modelMatrix, (float)glfwGetTime() + 20.0f * i, glm::vec3(0.5f, 1.0f, 0.0f));
    modelMatrix = glm::scale(modelMatrix, glm::vec3(0.8f, 0.8f, 0.8f));
    glm::mat4 viewMatrix(1.0);
    
//    viewMatrix = glm::translate(viewMatrix, glm::vec3(0.0f, 0.0f, -3.0f));
    
//    float radius = 10.0f;
//    float camX = sin(glfwGetTime()) * radius;
//    float camZ = cos(glfwGetTime()) * radius;
//    viewMatrix = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    
    viewMatrix = glm::lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);
    
    glm::mat4 projectionMatrix(1.0);
    projectionMatrix = glm::perspective(glm::radians(fov), (float)800/(float)800, 0.1f, 100.f);
    shader -> setMatrix4f("modelMatrix", glm::value_ptr(modelMatrix));
    shader -> setMatrix4f("viewMatrix", glm::value_ptr(viewMatrix));
    shader -> setMatrix4f("projectionMatrix", glm::value_ptr(projectionMatrix));
}

void Demo2::update(float pitch, float yaw) {
    glm::vec3 front;
    front.x = cos(glm::radians(pitch)) * cos(glm::radians(yaw));
    front.y = sin(glm::radians(pitch));
    front.z = cos(glm::radians(pitch)) * sin(glm::radians(yaw));
    cameraFront = glm::normalize(front);
}

void Demo2::zoomWith(float offset) {
    fov -= offset;
    if (fov <= 10.0f) {
        fov = 10.0f;
    }
    if (fov >= 60.0f) {
        fov = 60.0f;
    }
    std::cout << "fov: " << fov << std::endl;
}

void Demo2::draw() {
    shader -> use();
    // 先绑定两个纹理到对应的纹理单元, 然后定义哪个uniform采样器对应哪个纹理单元
    shader->setInt("texture0", 0);
    shader->setInt("texture1", 1);
    
//    updateTranform();
    
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture0);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture1);
    
    glBindVertexArray(VAO);
//    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    for (int i = 0; i < 10; i++) {
        updateTranform(i);
        glDrawArrays(GL_TRIANGLES, 0, 36);
    }
    glBindVertexArray(0);
}

void Demo2::moveForward() {
    cameraPosition += cameraSpeed * cameraFront;
}

void Demo2::moveBack() {
    cameraPosition -= cameraSpeed * cameraFront;
}

void Demo2::moveLeft() {
    cameraPosition -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

void Demo2::moveRight() {
    cameraPosition += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
